﻿//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;

//namespace Game2048.ConsoleApp
//{
//    class Program
//    {
//        static void Main(string[] args)
//        {
//        }
//    }
//}

using System;
using System.Collections.Generic;

namespace Console2048
{
    class Program
    {
        private static int[,] board = new int[4, 4];
        private static Random random = new Random();
        private static bool gameOver = false;

        static void Main(string[] args)
        {
            InitializeBoard();
            AddNewTile();
            AddNewTile();

            while (!gameOver)
            {
                PrintBoard();
                Console.WriteLine("Use W (Up), S (Down), A (Left), D (Right) to move. Press Q to quit.");
                var key = Console.ReadKey(true).Key;

                switch (key)
                {
                    case ConsoleKey.W:
                        MoveUp();
                        break;
                    case ConsoleKey.S:
                        MoveDown();
                        break;
                    case ConsoleKey.A:
                        MoveLeft();
                        break;
                    case ConsoleKey.D:
                        MoveRight();
                        break;
                    case ConsoleKey.Q:
                        gameOver = true;
                        break;
                    default:
                        Console.WriteLine("Invalid key! Use W, S, A, D to move or Q to quit.");
                        break;
                }

                if (IsGameOver())
                {
                    gameOver = true;
                    Console.Clear();
                    PrintBoard();
                    Console.WriteLine("Game Over!");
                }
                else
                {
                    AddNewTile();
                }
            }
        }

        private static void InitializeBoard()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    board[i, j] = 0;
                }
            }
        }

        private static void AddNewTile()
        {
            int emptyCells = 0;
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (board[i, j] == 0)
                    {
                        emptyCells++;
                    }
                }
            }

            if (emptyCells > 0)
            {
                int index = random.Next(16);
                int count = 0;
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (board[i, j] == 0 && count == index)
                        {
                            board[i, j] = 2;
                            return;
                        }
                        if (board[i, j] == 0)
                        {
                            count++;
                        }
                    }
                }
            }
        }

        private static void PrintBoard()
        {
            Console.Clear();
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    Console.Write(board[i, j] + "\t");
                }
                Console.WriteLine();
            }
        }

        private static void MoveUp()
        {
            for (int col = 0; col < 4; col++)
            {
                int[] column = new int[4];
                int idx = 0;
                for (int row = 0; row < 4; row++)
                {
                    if (board[row, col] != 0)
                    {
                        column[idx++] = board[row, col];
                    }
                }

                for (int i = 0; i < idx - 1; i++)
                {
                    if (column[i] == column[i + 1])
                    {
                        column[i] *= 2;
                        for (int j = i + 1; j < idx - 1; j++)
                        {
                            column[j] = column[j + 1];
                        }
                        idx--;
                    }
                }

                for (int row = 0; row < 4; row++)
                {
                    board[row, col] = (row < idx) ? column[row] : 0;
                }
            }
        }

        private static void MoveDown()
        {
            for (int col = 0; col < 4; col++)
            {
                int[] column = new int[4];
                int idx = 3;
                for (int row = 3; row >= 0; row--)
                {
                    if (board[row, col] != 0)
                    {
                        column[idx--] = board[row, col];
                    }
                }

                for (int i = 3; i > 0; i--)
                {
                    if (column[i] == column[i - 1])
                    {
                        column[i] *= 2;
                        for (int j = i - 1; j > 0; j--)
                        {
                            column[j] = column[j - 1];
                        }
                        idx++;
                    }
                }

                for (int row = 0; row < 4; row++)
                {
                    board[row, col] = (row > idx) ? column[row] : 0;
                }
            }
        }

        private static void MoveLeft()
        {
            for (int row = 0; row < 4; row++)
            {
                int[] line = new int[4];
                int idx = 0;
                for (int col = 0; col < 4; col++)
                {
                    if (board[row, col] != 0)
                    {
                        line[idx++] = board[row, col];
                    }
                }

                for (int i = 0; i < idx - 1; i++)
                {
                    if (line[i] == line[i + 1])
                    {
                        line[i] *= 2;
                        for (int j = i + 1; j < idx - 1; j++)
                        {
                            line[j] = line[j + 1];
                        }
                        idx--;
                    }
                }

                for (int col = 0; col < 4; col++)
                {
                    board[row, col] = (col < idx) ? line[col] : 0;
                }
            }
        }

        private static void MoveRight()
        {
            for (int row = 0; row < 4; row++)
            {
                int[] line = new int[4];
                int idx = 3;
                for (int col = 3; col >= 0; col--)
                {
                    if (board[row, col] != 0)
                    {
                        line[idx--] = board[row, col];
                    }
                }

                for (int i = 3; i > 0; i--)
                {
                    if (line[i] == line[i - 1])
                    {
                        line[i] *= 2;
                        for (int j = i - 1; j > 0; j--)
                        {
                            line[j] = line[j - 1];
                        }
                        idx++;
                    }
                }

                for (int col = 0; col < 4; col++)
                {
                    board[row, col] = (col > idx) ? line[col] : 0;
                }
            }
        }

        private static bool IsGameOver()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (board[i, j] == 0)
                    {
                        return false;
                    }

                    if (i > 0 && board[i, j] == board[i - 1, j])
                    {
                        return false;
                    }

                    if (j > 0 && board[i, j] == board[i, j - 1])
                    {
                        return false;
                    }
                }
            }

            return true;
        }
    }
}